/*
 * Copyright (c) 2011-2014, fortiss GmbH.
 * Licensed under the Apache License, Version 2.0.
 *
 * Use, modification and distribution are subject to the terms specified
 * in the accompanying license file LICENSE.txt located at the root directory
 * of this software distribution. A copy is available at
 * http://chromosome.fortiss.org/.
 *
 * This file is part of CHROMOSOME.
 *
 * $Id: calculateFunction.c 7805 2014-03-13 09:54:35Z geisinger $
 */

/**
 * \file
 *         Source file for function calculate in component calculator.
 *
 * \author
 *         This file has been generated by the CHROMOSOME Modeling Tool (XMT)
 *         (fortiss GmbH).
 */

/******************************************************************************/
/***   Includes                                                             ***/
/******************************************************************************/
#include "calculator/adv/calculator/include/calculateFunction.h"

#include "calculator/adv/calculator/include/calculateFunctionWrapper.h"
#include "calculator/adv/calculator/include/calculatorComponent.h"
#include "calculator/adv/calculator/include/calculatorComponentWrapper.h"
#include "calculator/adv/calculator/include/calculatorManifest.h"

#include "xme/core/logUtils.h"

#include "xme/hal/include/mem.h"

// PROTECTED REGION ID(CALCULATOR_ADV_CALCULATOR_CALCULATEFUNCTION_C_INCLUDES) ENABLED START
#include "xme/core/dataHandler/include/dataHandler.h"

#include <inttypes.h>
// PROTECTED REGION END

/******************************************************************************/
/***   Definitions                                                          ***/
/******************************************************************************/

// PROTECTED REGION ID(CALCULATOR_ADV_CALCULATOR_CALCULATEFUNCTION_C_DEFINITIONS) ENABLED START

// PROTECTED REGION END

/******************************************************************************/
/***   Variables                                                            ***/
/******************************************************************************/
/**
 * \brief  Variable holding the value of the required output port 'calculatorResponse'.
 *
 * \details If necessary initialize this in the init function.
 *          The value of this variable will be written to the port at the end of
 *          the step function.
 */
static calculator_topic_calculatorResponse_t
portCalculatorResponseData;

// PROTECTED REGION ID(CALCULATOR_ADV_CALCULATOR_CALCULATEFUNCTION_C_VARIABLES) ENABLED START

// PROTECTED REGION END

/******************************************************************************/
/***   Prototypes                                                           ***/
/******************************************************************************/

// PROTECTED REGION ID(CALCULATOR_ADV_CALCULATOR_CALCULATEFUNCTION_C_PROTOTYPES) ENABLED START

// PROTECTED REGION END

/******************************************************************************/
/***   Implementation                                                       ***/
/******************************************************************************/
xme_status_t
calculator_adv_calculator_calculateFunction_init
(
    calculator_adv_calculator_calculatorComponent_config_t* const componentConfig
)
{
    // PROTECTED REGION ID(CALCULATOR_ADV_CALCULATOR_CALCULATEFUNCTION_INITIALIZE_C) ENABLED START
    
    XME_UNUSED_PARAMETER(componentConfig);

    XME_LOG(XME_LOG_ALWAYS, "Calculator server started, awaiting requests from clients...\n");

    return XME_STATUS_SUCCESS;
    
    // PROTECTED REGION END
}

void
calculator_adv_calculator_calculateFunction_step
(
    calculator_adv_calculator_calculatorComponent_config_t* const componentConfig
)
{
    xme_status_t status[1];
    
    calculator_topic_calculatorRequest_t portCalculatorRequestData; // Required port.
    calculator_topic_calculatorResponse_t* portCalculatorResponseDataPtr = &portCalculatorResponseData;
    xme_core_component_requestDataHandle_t portCalculatorRequestRequestDataHandle = (xme_core_component_requestDataHandle_t)XME_CORE_COMPONENT_INVALID_REQUEST_DATA_HANDLE;
    
    (void)xme_hal_mem_set(&portCalculatorRequestData, 0u, sizeof(calculator_topic_calculatorRequest_t));
    
    status[0] = calculator_adv_calculator_calculatorComponentWrapper_readRequestHandlerPortCalculatorRequest(&portCalculatorRequestData, &portCalculatorRequestRequestDataHandle);
    
    {
        // PROTECTED REGION ID(CALCULATOR_ADV_CALCULATOR_CALCULATEFUNCTION_STEP_C) ENABLED START
        char operation = '?';
        double operand1 = (double) portCalculatorRequestData.operand1;

        XME_UNUSED_PARAMETER(componentConfig);

        if (XME_STATUS_SUCCESS == status[0])
        {
            switch (portCalculatorRequestData.operation)
            {
            case CALCULATOR_TOPIC_CALCULATORREQUEST_OPERATION_ADD:
                operation = '+';
                portCalculatorResponseData.result = operand1 + portCalculatorRequestData.operand2;
                break;
            case CALCULATOR_TOPIC_CALCULATORREQUEST_OPERATION_SUBTRACT:
                operation = '-';
                portCalculatorResponseData.result = operand1 - portCalculatorRequestData.operand2;
                break;
            case CALCULATOR_TOPIC_CALCULATORREQUEST_OPERATION_MULTIPLY:
                operation = '*';
                portCalculatorResponseData.result = operand1 * portCalculatorRequestData.operand2;
                break;
            case CALCULATOR_TOPIC_CALCULATORREQUEST_OPERATION_DIVIDE:
                operation = '/';
                if (0.0 != portCalculatorRequestData.operand2)
                {
                    portCalculatorResponseData.result = operand1 / portCalculatorRequestData.operand2;
                }
                else
                {
                    // TODO: Allow to respond with an error code/message
                    XME_LOG(XME_LOG_WARNING, "calculateFunction: Division by zero!\n");
                    portCalculatorResponseData.result = 0;
                }
                break;
            }
        }

        XME_LOG
        (
            XME_LOG_ALWAYS,
            "calculateFunction: Calculating %" PRIi32 " %c %" PRIi32 " = %f\n",
            portCalculatorRequestData.operand1,
            operation,
            portCalculatorRequestData.operand2,
            portCalculatorResponseData.result
        );

        // PROTECTED REGION END
    }
    
    status[0] = calculator_adv_calculator_calculatorComponentWrapper_writeResponseSenderPortCalculatorResponse(portCalculatorResponseDataPtr, &portCalculatorRequestRequestDataHandle);
    
    {
        // PROTECTED REGION ID(CALCULATOR_ADV_CALCULATOR_CALCULATEFUNCTION_STEP_2_C) ENABLED START
    
        // Nothing to do
    
        // PROTECTED REGION END
    }
}

void
calculator_adv_calculator_calculateFunction_fini
(
    calculator_adv_calculator_calculatorComponent_config_t* const componentConfig
)
{
    // PROTECTED REGION ID(CALCULATOR_ADV_CALCULATOR_CALCULATEFUNCTION_TERMINATE_C) ENABLED START
    
    // Nothing to do
    
    XME_UNUSED_PARAMETER(componentConfig);
    
    // PROTECTED REGION END
}

// PROTECTED REGION ID(CALCULATOR_ADV_CALCULATOR_CALCULATEFUNCTION_IMPLEMENTATION_C) ENABLED START

// PROTECTED REGION END
